package com.example.baseapp.activity

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.example.baseapp.R
import kotlinx.android.synthetic.main.activity_delegate.*
import kotlin.reflect.KProperty

/**
 * @作者：HuaCon
 *
 * @类描述：委托
 *
 */

class DelegateActivity : AppCompatActivity() {

companion object{
    const val TAG = "lazy"
}

    /**
     * 知识点 ：by lazy
     *这里的by lazy{}是懒加载函数
     * 项目开始 灵魂三问？ 先猜一下 1，2，3 的问题
     */
    //                👇  👇
    private val lists by lazy {
        Log.d(TAG, "1.类初始化的时候我这个字段走没走？")
        val dates = mutableListOf("Apple", "HuaWei", "Mi")
        dates.removeAt(0)
        dates.add("OppO")
        dates
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_delegate)
        demo()
    }


    private fun demo() {
        bt_test.setOnClickListener {

            Log.d(TAG, "2.这里有什么数据?->$lists")

            lists.add("VivO")
            Log.d(TAG, "3.这里有什么数据?->$lists")

            lists.forEach { Log.d(TAG, it) }
        }
    }
}

/**
 * 类委托：将一个类的具体实现委托给另一个类去完成
 * @param helper 就是这个类的辅助对象
 * 这样写存在的问题，如果还有几十甚至几百个方法，都需要用这个辅助对象去实现一遍？
 */
class MySet<T>(private val helper: HashSet<T>) : Set<T> {
    override val size: Int
        get() = helper.size

    override fun contains(element: T): Boolean = helper.contains(element)

    override fun containsAll(elements: Collection<T>): Boolean = helper.containsAll(elements)

    override fun isEmpty(): Boolean = helper.isEmpty()

    override fun iterator(): Iterator<T> = helper.iterator()
    //还有很多方法
    //......
    //......
    //......
}

/**
 * 通过使用关键字 by 在接上委托对象，就可以免去上面的一大堆样式模板代码了
 * 借用了类委托之后代码明显简化，如果需要复写某个方法，只需要单独复写那一个方法就可以了
 */
//                                                              👇
class DelegateMySet<T>(private val helper: HashSet<T>) : Set<T> by helper {

    /**
     * 委托属性：将一个属性（字段）的具体实现委托给另外一个类去完成
     */
    val p by MyDelegate()

    fun helloWord(str: String?) {
        Log.d("tag", "helloWord")
    }

    override fun isEmpty(): Boolean = false
}

/**
 * 当给p赋值的时候自动调用setValue，取值时自动调用 getValue
 * 这是一种标准的代码实现模板
 * 必须实现getValue()，setValue()这两个方法，且都要使用operator关键字声明
 */
class MyDelegate {
    private var propValue: Any? = null

    /**
     * @param delegateMySet 委托功能在什么类中使用
     * @param property 属性操作类，可用于获取各种属性相关值
     */
    operator fun <T> getValue(delegateMySet: DelegateMySet<T>, property: KProperty<*>): Any? {
        return propValue
    }

    operator fun <T> setValue(
        delegateMySet: DelegateMySet<T>,
        property: KProperty<*>,
        value: Any?
    ) {
        this.propValue = value
    }
}


/**
 * 模仿lazy实现一个同样的函数
 * @param block 接受一段任意类型的函数并返回
 * Ps：只有by是关键字，lazy只是一个高阶函数而已
 */
class Later<T>(val block: () -> T) {
    private var delegateValue: Any? = null

    //实现委托类的getValue函数 1.作用在任何类上面
    operator fun getValue(any: Any?, property: KProperty<*>): T {
        if (delegateValue === null) {
            //赋值给委托类属性
            delegateValue = block()
        }
        //转型返回这段函数
        return delegateValue as T
    }
}